A simple shader for doing per-Texel lighting and anti-aliasing in Godot.
shader_type spatial;
uniform sampler2D t: source_color;
varying flat vec3 normal;
// https://www.youtube.com/watch?v=d6tp43wZqps
// Texel ati-aliasing
vec2 texelAntiAliasingUVs(sampler2D tex, vec2 base_uv){
vec2 texture_size = vec2(textureSize(tex, 0));
vec2 box_size = clamp(fwidth(base_uv) * texture_size, 1e-5, 1.0);
vec2 texel = base_uv * texture_size - vec2(0.5) * box_size;
vec2 texel_offset = smoothstep(vec2(1.0) - box_size, vec2(1.0), vec2(fract(texel.x), fract(texel.y)));
vec2 uv = (floor(texel) + vec2(0.5) + texel_offset) * (1.0 / texture_size);
return uv;
}
// https://www.youtube.com/watch?v=2giKvEC-A3o
// https://discussions.unity.com/t/the-quest-for-efficient-per-texel-lighting/700574/20
vec4 texel_snap(vec4 value, vec2 base_uv, sampler2D tex)
{
vec2 texture_size = vec2(textureSize(t, 0));
vec2 texel_size = 1.0f / texture_size;
vec2 duvdx = dFdx(base_uv);
vec2 duvdy = dFdy(base_uv);
vec4 dvdx = dFdx(value);
vec4 dvdy = dFdy(value);
vec2 uv_center = (floor(base_uv * texture_size) / texture_size) + (texel_size * 0.5f);
//vec2 uv_center = texelAntiAliasingUVs(t, base_uv);
vec2 duv = uv_center - base_uv; // distance to texel center.
return value + (dvdx * (duv.x * duvdy.y - duv.y * duvdy.x) + dvdy * (duv.y * duvdx.x - duv.x * duvdx.y)) / (duvdx.x * duvdy.y - duvdy.x * duvdx.y);
}
void fragment() {
normal = texel_snap(vec4(NORMAL, 0.0), UV, t).xyz;
LIGHT_VERTEX = texel_snap(vec4(LIGHT_VERTEX, 0.0f), UV, t).xyz;
}
void light() {
DIFFUSE_LIGHT += clamp(dot(normal, LIGHT), 0.0, 1.0) * ATTENUATION * LIGHT_COLOR / PI;
}
Slightly more optimized fragment shader with derivatives.
void fragment() {
vec2 texture_size = vec2(textureSize(color, 0));
vec2 box_size = clamp(fwidthFine(UV) * texture_size, 1e-5, 1.0);
vec2 texel = UV * texture_size - vec2(0.5) * box_size;
vec2 texel_offset = smoothstep(vec2(1.0) - box_size, vec2(1.0), vec2(fract(texel.x), fract(texel.y)));
vec2 uv = (floor(texel) + vec2(0.5) + texel_offset) * (1.0 / texture_size);
ALBEDO = textureGrad(color, uv, dFdxFine(UV), dFdyFine(UV)).rgb;
}
by amber